package com.phenix.share.superwindow

import android.accessibilityservice.AccessibilityService
import android.accessibilityservice.AccessibilityServiceInfo
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import android.provider.Settings
import android.util.Log
import android.view.accessibility.AccessibilityManager
import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 浮窗服务管理器 - 支持自动重连的线程安全单例
 */
class SuperFloatingWindowManager private constructor() {

    // 核心状态
    private val isServiceConnected = AtomicBoolean(false)
    private val isReconnecting = AtomicBoolean(false)

    private val isWindowShown = AtomicBoolean(false)
    private val isMini = AtomicBoolean(false)
    private val isFocused = AtomicBoolean(false)

    var superFloatingWindowCreator: ISuperFloatingWindowCreator? = null
        private set

    private val mSuperFloatingWindowCallbacks =
        CopyOnWriteArraySet<ISuperFloatingWindowCallback>()

    // 重连配置
    private var mRetryCount = 0

    // 线程与Handler
    private var mHandlerThread: HandlerThread? = null
    private var mHandler: Handler? = null

    private val mDeathRecipient = IBinder.DeathRecipient {
        Log.w(TAG, "Service binder has died!")
        handleOnServiceDisconnected(null)
    }

    private val mConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, binder: IBinder) {
            synchronized(this@SuperFloatingWindowManager) {
                Log.d(TAG, "#onServiceConnected: $name, binder: $binder")

                try {
                    binder.linkToDeath(mDeathRecipient, 0)
                    isServiceConnected.set(true)
                    isReconnecting.set(false) // 停止重试
                    mRetryCount = 0            // 重置计数
                    mHandler?.removeCallbacksAndMessages(null) // 清理待执行任务
                    Log.i(TAG, "Service connected successfully. Retry count reset.")
                } catch (e: Exception) {
                    Log.e(TAG, "Failed to linkToDeath", e)
                }
            }
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            handleOnServiceDisconnected(name)
        }
    }

    private fun handleOnServiceDisconnected(name: ComponentName?) {
        synchronized(this@SuperFloatingWindowManager) {
            if (isServiceConnected.compareAndSet(true, false)) {
                Log.w(TAG, "Service($name) disconnected. Preparing to reconnect...")
                maybeScheduleReconnect()
            }
        }
    }

    /**
     * 绑定服务（线程安全）
     */
    private fun bindService(context: Context) {
        synchronized(this) {
            if (isServiceActive()) {
                Log.d(TAG, "#bindService: already connected, skip.")
                return
            }

            val intent = Intent(context, SuperFloatingWindowService::class.java)
            val flags = Context.BIND_AUTO_CREATE

            runCatching {
                val result = context.bindService(intent, mConnection, flags)
                Log.d(TAG, "#bindService result: $result")
                if (result) {
                    isServiceConnected.set(true)
                } else {
                    Log.w(TAG, "#bindService failed to bind service.")
                    // 绑定失败也视为断开，触发重连
                    maybeScheduleReconnect()
                }
            }.onFailure { e ->
                Log.e(TAG, "#bindService failed with exception", e)
                maybeScheduleReconnect()
            }
        }
    }

    /**
     * 解绑服务（线程安全）
     */
    private fun unbindService(context: Context) {
        synchronized(this) {
            if (isServiceConnected.compareAndSet(true, false)) {
                runCatching {
                    context.unbindService(mConnection)
                    Log.d(TAG, "Successfully unbound service.")
                }.onFailure { e ->
                    when (e) {
                        is IllegalArgumentException ->
                            Log.w(TAG, "Already unbound or not bound", e)

                        else ->
                            Log.e(TAG, "Unexpected error during unbind", e)
                    }
                }
            } else {
                Log.d(TAG, "Already unbound or not bound, skip unbind.")
            }

            // 取消所有重连计划
            isReconnecting.set(false)
            mHandler?.removeCallbacksAndMessages(null)
        }
    }

    // MARK: - 重连逻辑

    /**
     * 决定是否安排重连
     */
    private fun maybeScheduleReconnect() {
        if (isReconnecting.get() || mRetryCount >= MAX_RETRY) {
            Log.w(
                TAG,
                "Reconnect not allowed. isReconnecting=${isReconnecting.get()}, retryCount=$mRetryCount"
            )
            return
        }

        if (!isReconnecting.compareAndSet(false, true)) {
            return // 防止重复调度
        }

        val delay = calculateRetryDelay()
        Log.w(TAG, "Scheduling reconnect in ${delay}ms (attempt ${mRetryCount + 1}/$MAX_RETRY)")

        mHandler?.postDelayed({
            synchronized(this@SuperFloatingWindowManager) {
                if (isServiceActive() || !isReconnecting.get()) {
                    Log.d(TAG, "Reconnect canceled: already connected or canceled")
                    return@postDelayed
                }

                mRetryCount++
                Log.i(TAG, "Executing reconnect attempt $mRetryCount")
                bindService(appContext ?: return@postDelayed)
            }
        }, delay)
    }

    /**
     * 计算重试延迟（指数退避 + 随机抖动）
     */
    private fun calculateRetryDelay(): Long {
        // 指数退避：2^retry * base
        var delay =
            INITIAL_RETRY_DELAY * (1L shl mRetryCount.coerceAtMost(4)) // 最大 2^4 = 16 * 2s = 32s
        delay = delay.coerceAtMost(MAX_RETRY_DELAY)

        // 添加 ±20% 的随机抖动，避免雪崩
        val jitter = (delay * 0.2 * (Math.random() - 0.5) * 2).toLong() // ±20%
        return (delay + jitter).coerceAtLeast(1000)
    }

    // MARK: - Public API

    private var appContext: Context? = null

    /**
     * 初始化并绑定服务
     */
    fun initialize(context: Context, creator: ISuperFloatingWindowCreator) {
        this.appContext = context.applicationContext
        this.superFloatingWindowCreator = creator
        mHandlerThread = HandlerThread("SuperFloatingWindowServiceReconnect").apply {
            start()
            mHandler = Handler(looper)
        }

        Thread.setDefaultUncaughtExceptionHandler { t, e ->
            Log.e(TAG, "uncaughtException($t, $e)")
        }
        bindService(appContext!!)
        // 检查浮窗权限
        if (!requestOverlayPermission(context)) {
            Log.i(TAG, "To request overlay permission...")
        } else {
            Log.i(TAG, "Overlay permission has been granted.")
        }
    }

    /**
     * 释放资源，解绑服务，停止重连
     */
    fun release() {
        Log.d(TAG, "#release")
        appContext?.let {
            hide()
            unbindService(it)
            mSuperFloatingWindowCallbacks.removeIf { callback -> callback !is SuperFloatingWindowService }
            this.mHandler = null
            // 清理线程
            mHandlerThread?.quitSafely()
            this.mHandlerThread = null
            this.appContext = null
        }
    }

    /**
     * 当前服务是否已连接
     */
    fun isServiceActive(): Boolean = isServiceConnected.get()

    /**
     * 是否正在重连中
     */
    fun isReconnecting(): Boolean = isReconnecting.get()

    /**
     * 强制立即重试（可用于网络恢复后手动触发）
     */
    fun retryNow() {
        mHandler?.removeCallbacksAndMessages(null)
        mRetryCount = 0
        isReconnecting.set(true)
        mHandler?.post {
            appContext?.let { bindService(it) }
        }
    }

    fun addOnSuperFloatingWindowCallback(callback: ISuperFloatingWindowCallback) {
        mSuperFloatingWindowCallbacks.add(callback)
    }

    fun removeOnSuperFloatingWindowCallback(callback: ISuperFloatingWindowCallback) {
        mSuperFloatingWindowCallbacks.remove(callback)
    }

    fun isWindowShown() = isWindowShown.get()

    fun isMini() = isMini.get()

    fun isWindowFocused() = isFocused.get()

    fun show() {
        Log.d(TAG, "#show isWindowShown:${isWindowShown()}")
        if (isWindowShown.compareAndSet(false, true)) {
            notifyOnWindowVisibilityChanged()
        }
    }

    fun hide() {
        Log.d(TAG, "#hide isWindowShown:${isWindowShown()}")
        if (isWindowShown.compareAndSet(true, false)) {
            notifyOnWindowVisibilityChanged()
            reset()
        }
    }

    private fun reset() {
        isMini.set(false)
    }

    fun miniSize() {
        if (isMini.compareAndSet(false, true)) {
            if (isWindowShown()) {
                notifyOnWindowSizeChanged()
            } else {
                show()
            }
        }
    }

    fun restoreSize() {
        if (isMini.compareAndSet(true, false)) {
            notifyOnWindowSizeChanged()
        }
    }

    fun requestFocus(gainFocus: Boolean) {
        if (isFocused.compareAndSet(false, true)) {
            notifyOnWindowFocusChanged()
        }
    }

    private fun notifyOnWindowFocusChanged() {
        Log.d(
            TAG,
            "#notifyOnWindowFocusChanged isFocus:${isWindowFocused()} "
        )
        for (it in mSuperFloatingWindowCallbacks) {
            try {
                it.onWindowFocusChanged(isWindowFocused())
            } catch (e: Exception) {
                Log.e(TAG, "Error in notifyOnWindowFocusChanged callback", e)
            }
        }
    }

    // 通知所有回调
    private fun notifyOnWindowVisibilityChanged() {
        Log.d(
            TAG,
            "#notifyOnWindowVisibilityChanged isWindowShown:${isWindowShown()} "
        )
        for (it in mSuperFloatingWindowCallbacks) {
            try {
                it.onVisibilityChanged(isWindowShown())
            } catch (e: Exception) {
                Log.e(TAG, "Error in notifyOnWindowVisibilityChanged callback", e)
            }
        }
    }

    // 通知所有回调
    private fun notifyOnWindowSizeChanged() {
        Log.d(
            TAG,
            "#notifyOnWindowSizeChanged isMini:${isMini()}"
        )
        for (it in mSuperFloatingWindowCallbacks) {
            try {
                it.onWindowSizeChanged(isMini())
            } catch (e: Exception) {
                Log.e(TAG, "Error in notifyOnWindowSizeChanged callback", e)
            }
        }
    }

    // 通知所有回调
    fun notifyOnWindowPositionChanged(pointX: Int, pointY: Int) {
        Log.d(
            TAG,
            "#notifyOnWindowPositionChanged (x, y):($pointX, $pointY)"
        )
        for (it in mSuperFloatingWindowCallbacks) {
            try {
                it.onWindowPositionChanged(pointX, pointY)
            } catch (e: Exception) {
                Log.e(TAG, "Error in notifyOnWindowPositionChanged callback", e)
            }
        }
    }

    fun dump(): String {
        return "SuperFloatingWindowManager(isServiceConnected=$isServiceConnected, isReconnecting=$isReconnecting, isWindowShown=$isWindowShown, isMini=$isMini, superFloatingWindowCreator=$superFloatingWindowCreator, mSuperFloatingWindowCallbacks=$mSuperFloatingWindowCallbacks, appContext=$appContext)"
    }


    companion object {
        private const val TAG = "SuperFloatingWindowManager"

        private const val MAX_RETRY = 3
        private const val INITIAL_RETRY_DELAY: Long = 2000 // 2秒
        private const val MAX_RETRY_DELAY: Long = 10000    // 10秒

        @Volatile
        private var instance: SuperFloatingWindowManager? = null


        @JvmStatic
        fun getInstance(): SuperFloatingWindowManager {
            return instance ?: synchronized(this) {
                instance ?: SuperFloatingWindowManager().also { instance = it }
            }
        }

        @JvmStatic
        @SuppressLint("ObsoleteSdkInt")
        private fun requestOverlayPermission(context: Context): Boolean {
            val hasGranted =
                isAccessibilityEnabled(
                    context,
                    ComponentName(context, SuperFloatingWindowService::class.java).flattenToString()
                )
            if (!hasGranted) {
                val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(intent)

                return false
            }
            return true
        }

        private fun isAccessibilityEnabled(
            context: Context,
            serviceComponentName: String
        ): Boolean {
            val accessibilityManager =
                context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager

            val enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
                AccessibilityServiceInfo.FEEDBACK_ALL_MASK
            )
            return enabledServices.any { it.id == serviceComponentName }
        }
    }
}